////////////////////////////////////////////////////////////////////////////////
/*! \file
 * \brief The interface file for the MythMemory library.
 *
 * This library defines a few classes for handeling memory in different ways.
 * You can create inputs and outputs to and from memory and there are also
 * 2 allocator classes that can be used to create, construct, destruct and delete
 * objects across dynamically loaded libraries.
 *
 * \author Ivo Wingelaar
 * \date 2011
 * \version 0.1.0
 * \copyright GNU Lesser General Public License v3
 */
////////////////////////////////////////////////////////////////////////////////

#ifndef __MYTH_MEMORY_HPP_INCLUDED__
#define __MYTH_MEMORY_HPP_INCLUDED__

////////////////////////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////////////////////////
#include "MythStream.hpp"

////////////////////////////////////////////////////////////////////////////////
// Configuration
////////////////////////////////////////////////////////////////////////////////
#if (!defined _MYTH_MEMORY_EXTENSION_)
    #if ((!defined _MYTH_MEMORY_STATIC_LIBRARY_) && \
         (!defined _MYTH_MEMORY_DYNAMIC_LIBRARY_))
        #error Please define which version of the library you are using.
    #endif

    #ifdef _MYTH_WINDOWS_
        #ifdef _MYTH_MEMORY_STATIC_LIBRARY_
            #define _MYTH_MEMORY_API_
        #endif // _MYTH_MEMORY_STATIC_LIBRARY_

        #ifdef _MYTH_MEMORY_LIBRARY_
            #ifdef _MYTH_MEMORY_EXPORT_
                #define _MYTH_MEMORY_API_ __declspec(dllexport)
            #else
                #define _MYTH_MEMORY_API_ __declspec(dllimport)
            #endif // _MYTH_MEMORY_EXPORT_
        #endif // _MYTH_MEMORY_DYNAMIC_LIBRARY_
    #endif // _MYTH_WINDOWS_

    #ifdef _MYTH_LINUX_
        #define _MYTH_MEMORY_API_
    #endif // _MYTH_LINUX_
#endif // _MYTH_MEMORY_EXTENSION_

namespace Myth
{
////////////////////////////////////////////////////////////////////////////////
//! The namespace of the MythMemory library.
namespace Memory
{

#if (!defined _MYTH_MEMORY_EXTENSION_)

    //! Creates an input from a memory location.
    /*!
     * \return A pointer to an input from a memory location.
     * \param[in] stream_name Name of the stream.
     * \param[in] memory Pointer to a memory location.
     * \param[in] size Size of the memory in bytes.
     * \param[in] own_memory If true the object will delete the memory when it is destroyed.
     */
    extern "C" _MYTH_MEMORY_API_ Stream::Input* _MYTH_CALL_CONV_ create_input_memory(const std::string& stream_name, void* memory, uintptr_t size, bool own_memory);

    //! Creates an output to a memory location.
    /*!
     * \return A pointer to an output to a memory location.
     * \param[in] stream_name Name of the stream.
     * \param[in] memory Pointer to a memory location.
     * \param[in] size Size of the memory in bytes.
     * \param[in] own_memory If true the object will delete the memory when it is destroyed.
     */
    extern "C" _MYTH_MEMORY_API_ Stream::Output* _MYTH_CALL_CONV_ create_output_memory(const std::string& stream_name, void* memory, uintptr_t size, bool own_memory);

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the version of the MythMemory library.
    /*!
     * \return The version of the MythMemory library.
     */
    extern "C" _MYTH_MEMORY_API_ uint32_t _MYTH_CALL_CONV_ get_myth_memory_version(void);

#endif // _MYTH_MEMORY_EXTENSION_

//! Very simple allocator implementation, containers using it can be used across memory heaps.
template<typename T>
class Allocator
{
public:
    //! Virtual destructor.
    virtual ~Allocator()
    {
        //
    }

    //! Allocate memory for an array of objects.
    /*!
     * \return A pointer to an array of objects of the requested size.
     * \param[in] count The number of objects to request memory from.
     */
    T* allocate(size_t count)
    {
        return (T*)internal_new(count* sizeof(T));
    }

    //! Deallocate memory for an array of objects.
    /*!
     * \param[in] ptr A pointer to an array of objects.
     */
    void deallocate(T* ptr)
    {
        internal_delete(ptr);
    }

    //! Construct an element.
    /*!
     * \param[in] ptr A pointer to a location where you want to construct the new object.
     * \param[in] e The value you want to give to the constructed object.
     */
    void construct(T* ptr, const T& e)
    {
        new((void*)ptr) T(e);
    }

    //! Destruct an element
    /*!
     * \param[in] ptr A pointer to the object you want to destruct.
     */
    void destruct(T* ptr)
    {
        ptr->~T();
    }

protected:
    //! Internal allocation function.
    /*!
     * \return A pointer to an array of objects of the requested size.
     * \param[in] count The number of objects to request memory from.
     */
    void* internal_new(size_t count)
    {
        return operator new(count);
    }

    //! Internal deallocation function.
    /*!
     * \param[in] ptr A pointer to an array of objects.
     */
    void internal_delete(void* ptr)
    {
        operator delete(ptr);
    }
};

//! Fast allocator, only to be used in containers inside the same memory heap.
template<typename T>
class AllocatorFast
{
public:
    //! Allocate memory for an array of objects.
    /*!
     * \return A pointer to an array of objects of the requested size.
     * \param[in] count The number of objects to request memory from.
     */
    T* allocate(size_t count)
    {
        return (T*)operator new(count* sizeof(T));
    }

    //! Deallocate memory for an array of objects.
    /*!
     * \param[in] ptr A pointer to an array of objects.
     */
    void deallocate(T* ptr)
    {
        operator delete(ptr);
    }

    //! Construct an element.
    /*!
     * \param[in] ptr A pointer to a location where you want to construct the new object.
     * \param[in] e The value you want to give to the constructed object.
     */
    void construct(T* ptr, const T& e)
    {
        new((void*)ptr) T(e);
    }

    //! Destruct an element
    /*!
     * \param[in] ptr A pointer to the object you want to destruct.
     */
    void destruct(T* ptr)
    {
        ptr->~T();
    }
};

} // namespace Memory
} // namespace Myth

#endif // __MYTH_MEMORY_HPP_INCLUDED__
